import axios from 'axios'

// 定义响应数据类型
interface ApiResponse<T = any> {
  data: T
  code: number
  msg: string
  success: boolean
}

// 定义token响应类型
interface TokenResponse {
  access_token: string
  refresh_token: string
  expires_in: number
}

// 获取环境变量
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
const TOKEN_KEY = import.meta.env.VITE_TOKEN_KEY
const REFRESH_TOKEN_KEY = import.meta.env.VITE_REFRESH_TOKEN_KEY
const TOKEN_EXPIRES_KEY = import.meta.env.VITE_TOKEN_EXPIRES_KEY || 'token_expires_at'

/**
 * Token管理类 - 单例模式
 * 负责管理访问令牌和刷新令牌的存储、验证和刷新
 */
export class TokenManager {
  private static instance: TokenManager
  private refreshing = false
  private refreshSubscribers: Array<(token: string) => void> = []

  /**
   * 获取TokenManager单例实例
   */
  static getInstance(): TokenManager {
    return TokenManager?.instance ?? new TokenManager()
  }

  /**
   * 获取访问令牌
   */
  getAccessToken(): string | null {
    return localStorage.getItem(TOKEN_KEY)
  }

  /**
   * 获取刷新令牌
   */
  getRefreshToken(): string | null {
    return localStorage.getItem(REFRESH_TOKEN_KEY)
  }

  /**
   * 设置令牌
   * @param accessToken 访问令牌
   * @param refreshToken 刷新令牌
   * @param expiresIn 过期时间（秒）
   */
  setTokens(accessToken: string, refreshToken: string, expiresIn?: number): void {
    localStorage.setItem(TOKEN_KEY, accessToken)
    localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken)
    
    // 如果提供了过期时间，计算并存储过期时间戳
    if (expiresIn) {
      const expiresAt = Date.now() + (expiresIn * 1000) // expiresIn是秒，转换为毫秒
      localStorage.setItem(TOKEN_EXPIRES_KEY, expiresAt.toString())
    }
  }

  /**
   * 清除所有令牌
   */
  clearTokens(): void {
    localStorage.removeItem(TOKEN_KEY)
    localStorage.removeItem(REFRESH_TOKEN_KEY)
    localStorage.removeItem(TOKEN_EXPIRES_KEY)
  }

  /**
   * 检查token是否过期
   * @returns true表示已过期，false表示未过期
   */
  isTokenExpired(): boolean {
    const expiresAt = localStorage.getItem(TOKEN_EXPIRES_KEY)
    if (!expiresAt) {
      // 如果没有过期时间信息，认为token有效（向后兼容）
      return false
    }
    
    const expiresTimestamp = parseInt(expiresAt, 10)
    const now = Date.now()
    
    // 提前5分钟判断为过期，避免请求时刚好过期
    const bufferTime = 5 * 60 * 1000 // 5分钟的毫秒数
    return now >= (expiresTimestamp - bufferTime)
  }

  /**
   * 刷新令牌
   * @returns 新的访问令牌或null（刷新失败）
   */
  async refreshToken(): Promise<string | null> {
    const refreshToken = this.getRefreshToken()
    if (!refreshToken) {
      this.clearTokens()
      return null
    }

    if (this.refreshing) {
      // 如果正在刷新，返回一个Promise，等待刷新完成
      return new Promise((resolve) => {
        this.refreshSubscribers.push((token: string) => {
          resolve(token)
        })
      })
    }

    this.refreshing = true

    try {
      const response = await axios.post<ApiResponse<TokenResponse>>(
        `${API_BASE_URL}/auth/refresh`,
        { refresh_token: refreshToken }
      )

      if (response.data.success) {
        const { access_token, refresh_token, expires_in } = response.data.data
        this.setTokens(access_token, refresh_token, expires_in)
        
        // 通知所有等待的请求
        this.refreshSubscribers.forEach(callback => callback(access_token))
        this.refreshSubscribers = []
        
        return access_token
      } else {
        throw new Error('Token refresh failed')
      }
    } catch (error) {
      console.error('Token refresh error:', error)
      this.clearTokens()
      // 跳转到登录页
      window.location.href = '/login'
      return null
    } finally {
      this.refreshing = false
    }
  }

  /**
   * 检查是否有有效的访问令牌
   */
  hasValidToken(): boolean {
    const token = this.getAccessToken()
    return !!token && !this.isTokenExpired()
  }

  /**
   * 检查是否已登录
   */
  isLoggedIn(): boolean {
    return this.hasValidToken() || !!this.getRefreshToken()
  }
}

// 导出单例实例
export const tokenManager = TokenManager.getInstance()